package com.nlp.visualization.core.seg.imlp;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.CRF.CRFSegment;
import com.hankcs.hanlp.seg.NShort.NShortSegment;
import com.hankcs.hanlp.tokenizer.IndexTokenizer;
import com.hankcs.hanlp.tokenizer.NLPTokenizer;
import com.hankcs.hanlp.tokenizer.SpeedTokenizer;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import com.nlp.visualization.core.seg.EntityRecognizeOption;
import com.nlp.visualization.core.seg.ISegmentService;
import com.nlp.visualization.core.seg.SegmentType;
import com.nlp.visualization.core.seg.filter.SegFilter;
import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Service("iSegmentServiceDefaultImpl")
public class ISegmentServiceDefaultImpl implements ISegmentService {


    private Logger logger = LoggerFactory.getLogger(ISegmentService.class);
    private SegFilter segFilter;

    @Override
    public List<String> executeSeg(String text, SegmentType method) {

        SegFilter.FilterBuilder builder = new SegFilter.FilterBuilder();
        segFilter = builder.build();
        return chooseMethod(text, method);

    }

    @Override
    public List<String> executeSeg(String text, SegmentType method, SegFilter filter) {
        this.segFilter = filter;
        return chooseMethod(text, method);

    }

    @Override
    public List<String> executeSegWithNamedEntity(String text, SegFilter filter) {
        this.segFilter = filter;
        List<com.hankcs.hanlp.seg.common.Term> termList = HanLP.newSegment().enableAllNamedEntityRecognize(true).seg(text);
        return hanlpFormal(termList);
    }

    /**
     * 选择分词的方法
     *
     * @param text
     * @param method
     * @return
     */
    private List<String> chooseMethod(String text, SegmentType method) {
        switch (method) {
            case ANSJ_DIC:
                return segbyAnsjDic(text);
            case ANSJ_BASIC:
                return segbyAnsjBasic(text);
            case ANSJ_NLP:
                return segByAnsjNLP(text);
            case ANSJ_INDEX:
                return segbyAnsjIndex(text);
            case ANSJ_NORMAL:
                return segbyAnsjNormal(text);
            case HANLP_CRF:
                return segByHanLPCRF(text);
            case HANLP_INDEX:
                return segbyHanLPIndex(text);
            case HANLP_FASTDIC:
                return segByHanLPDic(text);
            case HANLP_STANDARK:
                return segbyHanLPStandard(text);
            case HANLP_N_SHORTEST:
                return segbyHanLPNShortest(text);
            case HANLP_NLP:
                return segbyHanLPNLP(text);
            default:
                return null;
        }
    }


    /**
     * ansj字典方式分词
     *
     * @param text 需要分词的文本
     * @return
     */
    private List<String> segbyAnsjDic(String text) {
        Result segResults = DicAnalysis.parse(text);
        return formal(segResults);
    }

    /**
     * ansj最细粒度分词
     *
     * @param text
     * @return
     */
    private List<String> segbyAnsjBasic(String text) {
        Result segResults = BaseAnalysis.parse(text);
        return formal(segResults);
    }

    /**
     * ansj普通分词
     *
     * @param text
     * @return
     */
    private List<String> segbyAnsjNormal(String text) {
        Result segResults = ToAnalysis.parse(text);
        return formal(segResults);
    }

    /**
     * ansj 索引分词
     *
     * @param text
     * @return
     */
    private List<String> segbyAnsjIndex(String text) {
        Result segResults = IndexAnalysis.parse(text);
        return formal(segResults);
    }

    /**
     * ansj nlp分词，可以发现新词
     *
     * @param text
     * @return
     */
    private List<String> segByAnsjNLP(String text) {
        Result segResults = NlpAnalysis.parse(text);
//        Result segResults = NlpAnalysis.parse(text);
        return formal(segResults);
    }

    /**
     * ansj方式分词的通用代码部分
     */
    private List<String> formal(Result segResults) {
        List<String> list = new ArrayList<>();
        Iterator iterator = segResults.getTerms().iterator();
        while (iterator.hasNext()) {
            Term term = (Term) iterator.next();
            String termName = term.getName();
            if (!segFilter.IsIncludeStopwords(term.getName()) && !termName.trim().equals("")) {
                list.add(filterEmoji(term.toString()));
            }

        }
        return list;
    }

    /**
     * hanlp方式分词通用处理部分
     *
     * @param termList
     * @return
     */
    private List<String> hanlpFormal(List<com.hankcs.hanlp.seg.common.Term> termList) {
        List<String> list = new ArrayList<>();
        Iterator iterator = termList.iterator();
        while (iterator.hasNext()) {
            com.hankcs.hanlp.seg.common.Term term = (com.hankcs.hanlp.seg.common.Term) iterator.next();
            if (!segFilter.IsIncludeStopwords(term.word) && !term.word.trim().equals("")) {
                list.add(filterEmoji(term.toString()));
            }

        }
        return list;
    }

    /**
     * HanLP的标准分词
     *
     * @param text
     * @return
     */
    private List<String> segbyHanLPStandard(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = StandardTokenizer.segment(text);
        return hanlpFormal(termList);
    }

    /**
     * HanLP的NLP分词
     *
     * @param text
     * @return
     */
    private List<String> segbyHanLPNLP(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = NLPTokenizer.segment(text);
        return hanlpFormal(termList);
    }

    /**
     * HanLP的索引分词
     *
     * @param text
     * @return
     */
    private List<String> segbyHanLPIndex(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = IndexTokenizer.segment(text);
        return hanlpFormal(termList);
    }


    /**
     * HanLP的N-最短路径分词
     *
     * @param text
     * @return
     */
    private List<String> segbyHanLPNShortest(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = new NShortSegment().enableAllNamedEntityRecognize(true).seg(text);
        return hanlpFormal(termList);
    }

    /**
     * CRF分词
     *
     * @param text
     * @return
     */
    private List<String> segByHanLPCRF(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = new CRFSegment().enableAllNamedEntityRecognize(true).seg(text);
        return hanlpFormal(termList);
    }


    /**
     * 极速分词，基于AhoCorasickDoubleArrayTrie实现的词典分词，适用于“高吞吐量”“精度一般”的场合
     *
     * @param text
     * @return
     */
    private List<String> segByHanLPDic(String text) {
        List<com.hankcs.hanlp.seg.common.Term> termList = SpeedTokenizer.segment(text);
        return hanlpFormal(termList);
    }

    private static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
                || (codePoint == 0xD)
                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

    /**
     * 过滤emoji 或者 其他非文字类型的字符
     *
     * @param source
     * @return
     */
    public static String filterEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return source;
        }
        StringBuilder buf = null;
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (isEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }
                buf.append(codePoint);
            }
        }
        if (buf == null) {
            return source;
        } else {
            if (buf.length() == len) {
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }
    }
}
